/* HCTL2032 based rotary encoder sketch
 *
 * $Id: hctl_2032_encoder.pde 33 2009-11-03 09:03:50Z bram.daams@donders.ru.nl $
 *
 */

const byte sel1   = 10;
const byte sel2   = 11;
const byte xy     = 12;
const byte oe     = 14;
const byte xreset = 15;
const byte yreset = 16;

const byte XAXIS = 1;
const byte YAXIS = 2;

// serial commands
const int cmd_GETX           = 'x';
const int cmd_GETY           = 'y';
const int cmd_GETXY          = 'z';
const int cmd_GETXYt         = 'a';
const int cmd_XRESET         = 'X';
const int cmd_YRESET         = 'Y';
const int cmd_RESETBOTH      = 'Z';
const int cmd_TOGGLETESTMODE = 't';


// clock frequency = 21.7khz

unsigned long t;
int           command;
boolean       testmode = false;
long          x = 0;
long          y = 0;

void setup() {

  // disable the bitsi input buffer
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);

  // set the address and reset bits as output
  pinMode(sel1,   OUTPUT);
  pinMode(sel2,   OUTPUT);
  pinMode(xy,     OUTPUT);
  pinMode(oe,     OUTPUT);
  pinMode(xreset, OUTPUT);
  pinMode(yreset, OUTPUT);

  // set the reset signals high (the reset pins on the HCTL-2032 are active low)
  digitalWrite(xreset, HIGH);
  digitalWrite(yreset, HIGH);

  // set the data bus as input
  BitsiOutPortInputMode();

  Serial.begin(115200);	// opens serial port, sets data rate
  Serial.println("RotaryEncoder $Revision: 33 $, Ready!");
}


void loop()                 
{
  if (Serial.available() > 0) {
    // read the incoming byte:
    command = Serial.read();

    switch(command) {
    case cmd_GETX:
      Serial.println(readEncoder(XAXIS));
      break;

    case cmd_GETY:
      Serial.println(readEncoder(YAXIS));
      break;

    case cmd_GETXY:
      // sample x and y at 'the same time'
      x = readEncoder(XAXIS);
      y = readEncoder(YAXIS);
      Serial.print(x);
      Serial.print(",");
      Serial.println(y);
      break;

    case cmd_GETXYt:
      // sample x and y and the timestamp at 'the same time'
      x = readEncoder(XAXIS);
      t = millis();
      y = readEncoder(YAXIS);

      Serial.print(x);
      Serial.print(",");
      Serial.print(y);
      Serial.print(",");
      Serial.println(t);
      break;

    case cmd_XRESET:
      resetx();
      break;

    case cmd_YRESET:
      resety();
      break;

    case cmd_RESETBOTH:
      resetx();
      resety();
      break;

    case cmd_TOGGLETESTMODE:
      testmode = !testmode;
      break;

    }
  }

  if (testmode) {
    x = readEncoder(XAXIS);
    y = readEncoder(YAXIS);

    // show values
    Serial.print("X ");
    Serial.print (x);

    Serial.print(" Y ");
    Serial.println(y);

    // wait 25 miliseconds
    delay(25);
  }
}



long readEncoder(byte axis) {

  long counter = 0;

  // select x or y counter
  if (axis == XAXIS)
    digitalWrite(xy, LOW);
  else {
    digitalWrite(xy, HIGH);
  }

  // step 1: read MSB
  // write address
  digitalWrite(sel1, LOW);
  digitalWrite(sel2, HIGH);
  digitalWrite(oe,   LOW);

  delayMicroseconds(60);

  // read data bus
  counter = readBitsiOutPort() << 24;

  // step 2: read 2nd byte
  digitalWrite(sel1, HIGH);
  counter = counter | readBitsiOutPort() << 16;

  // step 3: read 3rd byte
  digitalWrite(sel1, LOW);
  digitalWrite(sel2, LOW);
  counter = counter | readBitsiOutPort() << 8;

  // step 4: read LSB
  digitalWrite(sel1, HIGH);
  counter = counter | readBitsiOutPort();

  // step 5: complete inhibit logic reset
  digitalWrite(oe, HIGH);

  return counter;
}


void BitsiOutPortInputMode()
{
  // configure all the pins of the output port as inputs ;-)
  pinMode(2, INPUT);    
  pinMode(3, INPUT);
  pinMode(4, INPUT);    
  pinMode(5, INPUT);    
  pinMode(6, INPUT);    
  pinMode(7, INPUT);    
  pinMode(8, INPUT);    
  pinMode(9, INPUT);

  // enable internal pullup
  digitalWrite(2, HIGH);  
  digitalWrite(3, HIGH);  
  digitalWrite(4, HIGH);  
  digitalWrite(5, HIGH);  
  digitalWrite(6, HIGH);  
  digitalWrite(7, HIGH);  
  digitalWrite(8, HIGH);  
  digitalWrite(9, HIGH);
}


byte readBitsiOutPort()
{
  return  ((PIND & B11111100) >> 2) | ((PINB & B00000011) << 6);
}

void resetx()
{
  digitalWrite(xreset, LOW);
  delayMicroseconds(50);
  digitalWrite(xreset, HIGH);
}

void resety()
{
  digitalWrite(yreset, LOW);
  delayMicroseconds(50);
  digitalWrite(yreset, HIGH);
}














